﻿//==============================================================================
//  File Name   :   ThumbnailHandler.cs
//
//  Copyright © 2007 by Do Hong Ngoc. All rights reserved.
//
//  Distributable under GPL code license.
//  See terms of license at www.bbquyen.com.
//
//==============================================================================

// <fileinformation>
//   <summary>
//     This file defines the ThumbnailHandler class.
//   </summary>
//   <author name="Do Hong Ngoc" mail="whiterose1611vn@yahoo.co.uk"/>
//   <date>3/31/2007 10:07:13 AM</date>
//   <remarks>
//     
//   </remarks>
// </fileinformation>

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using BbqFramework.Drawing;
using DRAWING_Encoder = System.Drawing.Imaging.Encoder;
using BbqFramework.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.IO;
using BbqFramework;
using System.Web.Hosting;

namespace Bbq.Gallery.UI
{
	/// <summary>
	/// Thumbnail Image Viewer Control HttpHandler
	/// </summary>
	/// <example>
	/// To register the Thumbnail HttpHandler with your application, 
	/// add the following to the <system.web> section of your web.config.
	/// <!-- Register the Thumbnail HttpHandler -->
	/// <httpHandlers>
	/// <add verb="GET" path="ThumbnailHandler.ashx" type="Bbq.Gallery.UI.ThumbnailHandler"/>
	/// </httpHandlers>
	/// </example>
    public class ThumbnailHandler : IHttpAsyncHandler
    {
        private delegate object GetThumbnailDelegate(HttpContext context);

        #region Private fields
        private string _thumbnailMode = null;
        private Exception _ex = null;
        private HttpHandlerAsyncResult _ar = null;
        private GetThumbnailDelegate _thumbnail = null;
        #endregion

        #region IHttpHandler Members

        /// <summary>
		/// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"></see> instance.
		/// </summary>
		/// <value></value>
		/// <returns>true if the <see cref="T:System.Web.IHttpHandler"></see> instance is reusable; otherwise, false.</returns>
		public bool IsReusable
		{
			get { return false; }
		}

		/// <summary>
		/// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"></see> interface.
		/// </summary>
		/// <param name="context">An <see cref="T:System.Web.HttpContext"></see> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
		public void ProcessRequest(HttpContext context)
		{
		}

		#endregion

        #region Private functions
        MemoryStream fileDownloadMemoryStream = null;
        /// <summary>
        /// Gets the thumbnail.
        /// </summary>
        /// <param name="context">The context.</param>
        private object GetThumbnail(HttpContext context)
        {
            try
            {
                // Get the QueryString parameters passed
                HttpRequest request = context.Request;

                // Create a thumb image from the source image
                string path = null;

                FastBitmap processer = null;

                //Perform
                _thumbnailMode = request.QueryString[GalleryHelper.THUMBNAIL_MODE];
                switch (_thumbnailMode)
                {
                    case GalleryHelper.ThumbnailModes.Album:
                        GalleryAlbum album = new GalleryAlbum();
                        Gallery.GalleryProvider.SetAlbumID(album, Gallery.GalleryProvider.GetActualAlbumIdentity(request.QueryString[Gallery.GALLERY_ALBUM_ID]));
                        album.AttachHttpContext(context);
                        GalleryHelper.GetGalleryAlbumInfo(album);
                        GalleryItem highlight = GalleryHelper.GetHighlightItem(album);
                        album.DetachHttpContext();

                        if (highlight == null)
                            path = HostingEnvironment.MapPath(GalleryHelper.DefaultAlbumThumbnail);
                        else
                            path = GalleryHelper.GetPhysicalPath(highlight.PathFromRoot);
                        processer = new FastBitmap(path);
                        if (processer.Width != GalleryHelper.GalleryAlbumThumbnailX || processer.Height != GalleryHelper.GalleryAlbumThumbnailY)
                            processer.Resize(GalleryHelper.GalleryAlbumThumbnailX, GalleryHelper.GalleryAlbumThumbnailY, true, true);
                        processer.SetResolution(96, 96);
                        using (Graphics graphic = Graphics.FromImage((Image)processer))
                        {
                            graphic.SmoothingMode = SmoothingMode.AntiAlias;
                            graphic.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
                            string itemCount = request[Gallery.GALLERY_ITEM_COUNT];
                            Font font = SystemFonts.IconTitleFont;
                            SizeF size = graphic.MeasureString(itemCount, font);
                            float x = GalleryHelper.GalleryAlbumThumbnailX - size.Width - 1;
                            float y = GalleryHelper.GalleryAlbumThumbnailY - size.Height;
                            graphic.DrawString(itemCount, font, Brushes.White, x + 1, y + 1);
                            graphic.DrawString(itemCount, font, Brushes.Red, x, y);
                        }
                        return processer;
                    case GalleryHelper.ThumbnailModes.Item:
                        //Get the current item
                        path = Gallery.GalleryProvider.GetActualItemIdentity(request[Gallery.GALLERY_ITEM_ID]);
                        //
                        //...............need pass HttpContext object to GetGalleryItemInfo
                        //
                        GalleryItem item = Gallery.GalleryProvider.GetGalleryItemInfo(path);
                        if (item.IsExternal)
                        {
                            string thumbnailImageUrl = item.ThumbnailUrl;
                            if (string.IsNullOrEmpty(thumbnailImageUrl))
                                thumbnailImageUrl = item.Url;
                            //using (BbqFramework.Net.FileDownloader downloader = new BbqFramework.Net.FileDownloader())
                            //{
                            //    downloader.SaveDataBlock += new EventHandler<BbqFramework.Net.SaveDataBlockEventArgs>(downloader_SaveDataBlock);
                            //    fileDownloadMemoryStream = new MemoryStream();
                            //    downloader.Download(thumbnailImageUrl);
                            //    downloader.SaveDataBlock -= new EventHandler<BbqFramework.Net.SaveDataBlockEventArgs>(downloader_SaveDataBlock);
                            //}
                            //downloader.Download
                            System.Net.WebRequest imgRequest = System.Net.WebRequest.Create(thumbnailImageUrl);
                            //imgRequest.Proxy = System.Net.WebRequest.DefaultWebProxy;
                            //imgRequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
                            //imgRequest.PreAuthenticate = true;
                            System.Net.WebResponse imgResponse = imgRequest.GetResponse();
                            //if (fileDownloadMemoryStream != null && fileDownloadMemoryStream.Length>0)
                            {
                                //Bitmap bitmap = new Bitmap(fileDownloadMemoryStream);
                                Bitmap bitmap = new Bitmap(imgResponse.GetResponseStream());
                                processer = new FastBitmap(bitmap);
                                imgResponse.Close();
                            }
                        }
                        else
                        {
                            path = GalleryHelper.GetPhysicalPath(path);
                            processer = new FastBitmap(path);
                        }
                        if (processer != null && processer.Performable)
                        {
                            if (processer.Width != GalleryHelper.GalleryItemThumbnailX || processer.Height != GalleryHelper.GalleryItemThumbnailY)
                                processer.Resize(GalleryHelper.GalleryItemThumbnailX, GalleryHelper.GalleryItemThumbnailY, true, true);

                            return processer;
                        }
                        return null;
                    case GalleryHelper.ThumbnailModes.Download:
                        path = Gallery.GalleryProvider.GetActualItemIdentity(request[Gallery.GALLERY_ITEM_ID]);
                        path = GalleryHelper.GetPhysicalPath(path);
                        return path;
                }
                return null;
            }
            catch (Exception ex)
            {
                _ex = ex;
                _ar.CompleteCall();
                //TODO: Consider to return a notification image.
                return null;
            }
            finally
            {
                if (fileDownloadMemoryStream != null)
                    fileDownloadMemoryStream.Close();
            }
        }

        /// <summary>
        /// Handles the SaveDataBlock event of the downloader control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="BbqFramework.Net.SaveDataBlockEventArgs"/> instance containing the event data.</param>
        void downloader_SaveDataBlock(object sender, BbqFramework.Net.SaveDataBlockEventArgs e)
        {
            BbqFramework.Net.FileDownloader downloader = (BbqFramework.Net.FileDownloader)sender;
            fileDownloadMemoryStream.Write(e.Data, (int)fileDownloadMemoryStream.Position, e.Data.Length); 
        }

        /// <summary>
        /// Gets the thumnail completed.
        /// </summary>
        /// <param name="ar">The ar.</param>
        private void GetThumnailCompleted(IAsyncResult ar)
        {
            if (_ex == null)
            {
                //Analyze HTTP response
                HttpContext context = (HttpContext)ar.AsyncState;
                HttpRequest request = context.Request;
                //Sets the response for thumbnail
                HttpResponse response = context.Response;
                response.BufferOutput = false;  //don't need buffer for image data.
                response.Cache.SetExpires(DateTime.Now.AddMinutes(15));
                response.Cache.SetCacheability(HttpCacheability.Public);
                response.Cache.SetSlidingExpiration(true);

                object result = _thumbnail.EndInvoke(ar);
                if (result != null)
                {
                    switch (_thumbnailMode)
                    {
                        case GalleryHelper.ThumbnailModes.Album:
                        case GalleryHelper.ThumbnailModes.Item:
                            //Image thumbnail type
                            ImageCodecInfo codecInfos = null;
                            EncoderParameters encoderParameters = null;
                            string thumbnailImageType = request[GalleryHelper.THUMBNAIL_IMAGETYPE];
                            switch (thumbnailImageType)
                            {
                                case "gif":
                                    codecInfos = CodecInfos.GIF;
                                    break;
                                default:	//jpeg
                                    EncoderParameter qualityParameter = new EncoderParameter(DRAWING_Encoder.Quality, GalleryHelper.ThumbnailCompression);
                                    encoderParameters = new EncoderParameters(1);
                                    encoderParameters.Param[0] = qualityParameter;
                                    codecInfos = CodecInfos.JPEG;
                                    break;
                            }
                            response.ContentType = codecInfos.MimeType;

                            FastBitmap fBitmap = (FastBitmap)result;
                            Bitmap bitmap = fBitmap.ToBitmap();
                            bitmap.Save(response.OutputStream, codecInfos, encoderParameters);
                            fBitmap.Dispose();
                            break;
                        case GalleryHelper.ThumbnailModes.Download:
                            string path = (string)result;
                            response.ContentType = "application/octet-stream";
                            response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlPathEncode(Path.GetFileName(path)));
                            response.TransmitFile(path);
                            break;
                        default:
                            break;
                    }
                }
                response.End();
                //Complete the request 
                _ar.CompleteCall();
            }
        }
        #endregion

        #region IHttpAsyncHandler Members

        /// <summary>
        /// Begins the process request.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="cb">The cb.</param>
        /// <param name="extraData">The extra data.</param>
        /// <returns></returns>
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
        {
            // Instantiate a HttpHandlerAsyncResult
            _ar = new HttpHandlerAsyncResult(cb, extraData);

            _thumbnail = new GetThumbnailDelegate(this.GetThumbnail);
            _thumbnail.BeginInvoke(context, new AsyncCallback(this.GetThumnailCompleted), context);

            // Return an IAsyncResult that delays EndProcessRequest until
            // the final asynchronous Web service call has completed
            return _ar;
        }

        /// <summary>
        /// Provides an asynchronous process End method when the process ends.
        /// </summary>
        /// <param name="result">An <see cref="T:System.IAsyncResult"/> that contains information about the status of the process.</param>
        public void EndProcessRequest(IAsyncResult result)
        {
            if (_ex != null)
            {
                // If an exception was thrown, rethrow it
                throw _ex;
            }
        }

        #endregion
    }
}
